<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Socket.IO 实时通信示例</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.socket.io/4.4.1/socket.io.min.js"></script>
    
    <!-- Tailwind CSS 配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#165DFF',
                        success: '#00B42A',
                        danger: '#F53F3F',
                        warning: '#FF7D00',
                        dark: '#1D2129',
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    
    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .animate-pulse-slow {
                animation: pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
            }
            .bg-gradient-blue {
                background: linear-gradient(135deg, #165DFF 0%, #4080FF 100%);
            }
        }
    </style>
</head>
<body class="font-inter bg-gray-50 min-h-screen flex flex-col">
    <!-- 顶部导航栏 -->
    <header class="bg-gradient-blue text-white shadow-md">
        <div class="container mx-auto px-4 py-4 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-comments text-2xl"></i>
                <h1 class="text-xl md:text-2xl font-bold">Socket.IO 实时通信示例1</h1>
            </div>
            <div id="connection-status" class="flex items-center">
                <span id="status-icon" class="inline-block w-3 h-3 rounded-full bg-warning animate-pulse mr-2"></span>
                <span id="status-text">连接中...</span>
            </div>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="flex-grow container mx-auto px-4 py-8">
        <div class="max-w-3xl mx-auto bg-white rounded-xl shadow-lg overflow-hidden">
            <!-- 消息展示区 -->
            <div id="messages" class="h-96 overflow-y-auto p-4 bg-gray-50 border-b border-gray-200">
                <div class="text-center text-gray-500 py-4">
                    <i class="fa fa-info-circle mr-2"></i>消息将显示在这里
                </div>
            </div>

            <!-- 输入区 -->
            <div class="p-4">
                <div class="flex space-x-3">
                    <input 
                        type="text" 
                        id="message-input" 
                        placeholder="输入消息..." 
                        class="flex-grow px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all"
                    >
                    <button 
                        id="send-button" 
                        class="bg-primary hover:bg-primary/90 text-white px-6 py-2 rounded-lg transition-all disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
                        disabled
                    >
                        <i class="fa fa-paper-plane mr-2"></i>发送
                    </button>
                </div>
            </div>
        </div>

        <!-- 配置区 -->
        <div class="mt-8 max-w-3xl mx-auto bg-white rounded-xl shadow-lg p-6">
            <h2 class="text-lg font-semibold mb-4 flex items-center">
                <i class="fa fa-cog mr-2 text-primary"></i>连接配置
            </h2>
            <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                <div>
                    <label for="server-url" class="block text-sm font-medium text-gray-700 mb-1">服务器地址</label>
                    <input 
                        type="text" 
                        id="server-url" 
                        value="http://localhost:3000" 
                        class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all"
                    >
                </div>
                <div>
                    <label for="username" class="block text-sm font-medium text-gray-700 mb-1">用户名</label>
                    <input 
                        type="text" 
                        id="username" 
                        value="访客" 
                        class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all"
                    >
                </div>
            </div>
            <div class="mt-4">
                <button 
                    id="connect-button" 
                    class="bg-success hover:bg-success/90 text-white px-6 py-2 rounded-lg transition-all flex items-center"
                >
                    <i class="fa fa-plug mr-2"></i><span id="connect-text">连接</span>
                </button>
            </div>
        </div>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark text-white py-6 mt-8">
        <div class="container mx-auto px-4 text-center">
            <p>© 2023 Socket.IO 示例 | 使用 Tailwind CSS 和 Font Awesome 构建</p>
        </div>
    </footer>

    <script>
        // 全局变量
        let socket;
        let isConnected = false;

        // DOM 元素
        const serverUrlInput = document.getElementById('server-url');
        const usernameInput = document.getElementById('username');
        const connectButton = document.getElementById('connect-button');
        const connectText = document.getElementById('connect-text');
        const messageInput = document.getElementById('message-input');
        const sendButton = document.getElementById('send-button');
        const messagesDiv = document.getElementById('messages');
        const statusIcon = document.getElementById('status-icon');
        const statusText = document.getElementById('status-text');

        // 连接/断开连接
        connectButton.addEventListener('click', () => {
            if (isConnected) {
                disconnect();
            } else {
                connect();
            }
        });

        // 发送消息
        sendButton.addEventListener('click', sendMessage);
        messageInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                sendMessage();
            }
        });

        // 连接到服务器
        function connect() {
            const serverUrl = serverUrlInput.value.trim();
            if (!serverUrl) {
                showNotification('请输入服务器地址', 'warning');
                return;
            }

            // 更新UI状态
            updateConnectionStatus('connecting');
            connectText.textContent = '断开';
            connectButton.classList.remove('bg-success', 'hover:bg-success/90');
            connectButton.classList.add('bg-danger', 'hover:bg-danger/90');

            // 创建Socket.IO实例
            socket = io(serverUrl, {
                autoConnect: false,
                reconnection: true,
                reconnectionAttempts: 5,
                reconnectionDelay: 1000
            });

            // 注册事件监听器
            registerSocketEvents();

            // 连接
            socket.connect();
        }

        // 断开连接
        function disconnect() {
            if (socket) {
                socket.disconnect();
                socket = null;
            }
            updateConnectionStatus('disconnected');
            connectText.textContent = '连接';
            connectButton.classList.remove('bg-danger', 'hover:bg-danger/90');
            connectButton.classList.add('bg-success', 'hover:bg-success/90');
            isConnected = false;
            sendButton.disabled = true;
        }

        // 注册Socket.IO事件
        function registerSocketEvents() {
            // 连接成功
            socket.on('connect', () => {
                isConnected = true;
                updateConnectionStatus('connected');
                sendButton.disabled = false;
                showNotification(`已连接到服务器: ${socket.io.uri}`, 'success');
                
                // 发送加入消息
                const username = usernameInput.value.trim() || '匿名用户';
                socket.emit('join', { username });
            });

            // 断开连接
            socket.on('disconnect', (reason) => {
                isConnected = false;
                sendButton.disabled = true;
                
                if (reason === 'io server disconnect') {
                    // 服务器主动断开，需要手动重连
                    showNotification('服务器断开连接', 'danger');
                } else {
                    // 其他原因断开，会自动重连
                    updateConnectionStatus('reconnecting');
                    showNotification(`连接断开，正在重连...`, 'warning');
                }
            });

            // 重连尝试
            socket.on('reconnect_attempt', (attempt) => {
                showNotification(`尝试重连 (${attempt}/5)`, 'warning');
            });

            // 重连失败
            socket.on('reconnect_failed', () => {
                updateConnectionStatus('disconnected');
                showNotification('重连失败，请检查服务器地址', 'danger');
                connectText.textContent = '连接';
                connectButton.classList.remove('bg-danger', 'hover:bg-danger/90');
                connectButton.classList.add('bg-success', 'hover:bg-success/90');
            });

            // 接收消息
            socket.on('message', (data) => {
                addMessage(data, false);
            });

            // 系统消息
            socket.on('system', (message) => {
                addSystemMessage(message);
            });

            // 错误处理
            socket.on('connect_error', (error) => {
                updateConnectionStatus('disconnected');
                showNotification(`连接错误: ${error.message}`, 'danger');
                connectText.textContent = '连接';
                connectButton.classList.remove('bg-danger', 'hover:bg-danger/90');
                connectButton.classList.add('bg-success', 'hover:bg-success/90');
            });
        }

        // 发送消息
        function sendMessage() {
            const message = messageInput.value.trim();
            if (!message) return;

            const username = usernameInput.value.trim() || '匿名用户';
            const data = {
                username,
                message,
                timestamp: new Date().toISOString()
            };

            // 显示自己发送的消息
            addMessage(data, true);
            
            // 发送消息到服务器
            socket.emit('message', data);
            
            // 清空输入框
            messageInput.value = '';
            messageInput.focus();
        }

        // 添加消息到消息区
        function addMessage(data, isSelf) {
            const { username, message, timestamp } = data;
            const date = new Date(timestamp);
            const timeStr = date.toLocaleTimeString();
            
            const messageClass = isSelf 
                ? 'bg-primary/10 text-dark rounded-t-lg rounded-bl-lg' 
                : 'bg-gray-100 text-dark rounded-t-lg rounded-br-lg';
            
            const alignClass = isSelf ? 'ml-auto' : 'mr-auto';
            
            const messageHTML = `
                <div class="flex ${isSelf ? 'flex-row-reverse' : 'flex-row'} mb-4">
                    <div class="w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center mr-2 ${isSelf ? 'ml-2' : ''}">
                        <span class="text-primary font-bold">${username.charAt(0).toUpperCase()}</span>
                    </div>
                    <div class="max-w-[80%]">
                        <div class="flex items-center text-xs text-gray-500 mb-1">
                            <span class="font-medium ${isSelf ? 'text-primary' : 'text-gray-700'}">${username}</span>
                            <span class="ml-2">${timeStr}</span>
                        </div>
                        <div class="${messageClass} p-3 shadow-sm">
                            <p>${message}</p>
                        </div>
                    </div>
                </div>
            `;
            
            messagesDiv.insertAdjacentHTML('beforeend', messageHTML);
            scrollToBottom();
        }

        // 添加系统消息
        function addSystemMessage(message) {
            const messageHTML = `
                <div class="text-center my-2">
                    <span class="inline-block bg-gray-200 text-gray-700 text-xs px-3 py-1 rounded-full">
                        ${message}
                    </span>
                </div>
            `;
            
            messagesDiv.insertAdjacentHTML('beforeend', messageHTML);
            scrollToBottom();
        }

        // 显示通知
        function showNotification(message, type = 'info') {
            const notificationHTML = `
                <div class="text-center my-2">
                    <span class="inline-block px-3 py-1 rounded-full text-sm ${
                        type === 'success' ? 'bg-success/20 text-success' : 
                        type === 'warning' ? 'bg-warning/20 text-warning' : 
                        type === 'danger' ? 'bg-danger/20 text-danger' : 
                        'bg-gray-200 text-gray-700'
                    }">
                        ${message}
                    </span>
                </div>
            `;
            
            messagesDiv.insertAdjacentHTML('beforeend', notificationHTML);
            scrollToBottom();
        }

        // 更新连接状态
        function updateConnectionStatus(status) {
            switch (status) {
                case 'connecting':
                    statusIcon.className = 'inline-block w-3 h-3 rounded-full bg-warning animate-pulse mr-2';
                    statusText.textContent = '连接中...';
                    break;
                case 'connected':
                    statusIcon.className = 'inline-block w-3 h-3 rounded-full bg-success mr-2';
                    statusText.textContent = '已连接';
                    break;
                case 'reconnecting':
                    statusIcon.className = 'inline-block w-3 h-3 rounded-full bg-warning animate-pulse mr-2';
                    statusText.textContent = '重连中...';
                    break;
                case 'disconnected':
                    statusIcon.className = 'inline-block w-3 h-3 rounded-full bg-danger mr-2';
                    statusText.textContent = '已断开';
                    break;
            }
        }

        // 滚动到底部
        function scrollToBottom() {
            messagesDiv.scrollTop = messagesDiv.scrollHeight;
        }
    </script>
</body>
</html>    